home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-08 | 23.1 KB | 754 lines | [TEXT/KAHL] |
- /*====================================================================================
- File: Relative Time Strings.c
- Written by: Chris Hufford CIS: 70076,1707
- Geoff Hufford CIS: 72627,3511
-
- Description:
- These routines were written for and used in our Shareware program called
- Eye On The Clock. These routines will take two dates and times and create a
- string, in MANY different formats, of how much time there is between the two
- dates and times. Basically you need to load up the Count_Rec structure and call
- Get_Rel_Time_Str and your done.
-
- These routines reference 'STR#' resource 129 for all text used to build the string
-
- There are many supporting routines for both time/date stuff as well as strings
- which may be useful on their own.
-
- Here is an example of loading up the Count_Rec:
-
- Count_Rec time_rec;
- Str255 the_str;
-
- time_rec.Display.fractional = FALSE;
- time_rec.Display.significant = FALSE;
- time_rec.Display.count_days = FALSE;
- time_rec.Display.hide_zeros = FALSE;
- time_rec.Display.allow_clock_display = FALSE;
- time_rec.Display.allow_day_rounding = FALSE;
- time_rec.Display.abbreviated = FALSE;
-
- time_rec.Target_In_Secs = 2840227200; // target time to display (in seconds) 1/1/90
- time_rec.From_In_Secs = 3000000000; // from time to display (in seconds)
-
- // you may add only the items which you want displayed:
- time_rec.Display.display_items = year + month + week + day + hour + minute + second;
-
- Get_Rel_Time_Str (&time_rec, the_str);
- // then display or use the_str)
- =====================================================================================*/
-
- ////////////////////////
- // Includes
- ////////////////////////
- #include "Relative Time Strings.h"
-
- ////////////////////////
- // Internal Prototypes
- ////////////////////////
- void Setup_Significant (Display_Items* display, Display_Type_Ptr display_ptr, unsigned long the_secs);
- unsigned long Month_Secs(short the_month, short the_year);
- void Float2String (float the_num, Str255 the_string, short places);
- void Append_String (Str255 source_string, Str255 append_string, Boolean trailing_space);
- void Append_Num2String (long the_num, Str255 the_string, Boolean leading_zero);
- void Append_Seperator( Str255 the_str );
- void Determine_Display_Elements (Display_Type_Ptr display);
-
- ////////////////////////
- // Constants
- ////////////////////////
- enum{
- Time_StringsID =129,
- yearString =1,
- yearsString,
- yrString,
- monthString,
- monthsString,
- moString,
- weekString,
- weeksString,
- wkString,
- dayString,
- daysString,
- dString,
- hourString,
- hoursString,
- hString,
- minuteString,
- minutesString,
- mString,
- secondString,
- secondsString,
- sString,
- agoString,
- untilString,
- countdaysString
- };
-
- /*====================================================================================
- Name: Get_Rel_Time_Str
- Description:
- Send it a Count_Rec_Ptr and it will return a formated string of the time
- difference between the two times sent in the Count_Rec
- Last revision:
- __________________________________________________________________________________
-
- Input:
- Count_Rec_Ptr pointer to a Count_Rec structure which should be loaded with
- a from time, a to time, and all display options
- the_str pointer to a Str255 which will be used to return the string
- Output:
- the_str the returned formated string
- =====================================================================================*/
- void Get_Rel_Time_Str (Count_Rec_Ptr count_ptr, Str255 the_str)
- {
- Display_Elements elements;
-
- Determine_Display_Elements (&count_ptr->Display);
- Calculate_Rel_Time_Str(count_ptr, &elements);
- Assemble_Time_String (&elements, the_str, count_ptr->Display.abbreviated);
- }
-
-
- /*====================================================================================
- Name: Calculate_Rel_Time_Str
- Description:
- You must call Determine_Display_Elements at some point before making this call.
- This is used by Get_Rel_Time_Str but could be useful to call on it's own. It
- is passed a pointer to a Count_Rec and a pointer to Display_Elements. It does
- everything needed to load Display_Elements which is used to assemble the output
- string by Assemble_Time_String.
- Last revision:
- __________________________________________________________________________________
-
- Input:
- Count_Rec_Ptr pointer to the Count_Rec that is being calculated
- Display_Elements_Ptr pointer to an empty Display_Elements which will be
- filled upon exit
- Output:
- Display_Elements_Ptr returns filled up and ready for Assemble_Time_String
- =====================================================================================*/
- void Calculate_Rel_Time_Str (Count_Rec_Ptr count_ptr, Display_Elements_Ptr element_ptr)
- {
- long current_day, temp;
- long next_year, next_month, offset = 0;
- unsigned long target_secs, current_secs;
- unsigned long years,months,weeks,days,hours,minutes,seconds,the_secs;
- float fraction;
- Boolean in_past, keep_counting;
- Display_Items display;
- Display_Type_Ptr display_ptr;
- DateTimeRec current_daterec, target_daterec;
- short places, year_index, month_index, four_years=0;
-
-
- target_secs = count_ptr->Target_In_Secs;
- current_secs = count_ptr->From_In_Secs;
-
- display_ptr = &count_ptr->Display;
- display = display_ptr->display_items;
-
- if (target_secs < current_secs)
- {
- in_past = TRUE;
- the_secs = current_secs - target_secs;
- if (display_ptr->significant)
- Setup_Significant (&display, display_ptr, the_secs);
- offset = target_secs % DAY_SECS; // Calculate Offset to Round Days to Midnight
- }
- else
- {
- in_past = FALSE;
- the_secs = target_secs - count_ptr->From_In_Secs;
- if (display_ptr->significant)
- Setup_Significant (&display, display_ptr, the_secs);
- offset = DAY_SECS - (target_secs % DAY_SECS); // Calculate Offset to Round Days to Midnight
- }
-
- if (display_ptr->last_item & calendarDayMask && !display_ptr->fractional && display_ptr->allow_day_rounding)
- {
- the_secs += offset; // Apply calendar day offset
- offset = 0; // Zero it so it cant be applied twice
- }
-
- if (display_ptr->count_days && in_past) // if we should count event date then add a day to past
- {
- the_secs += DAY_SECS; // events
- the_secs += offset; // Apply calendar day offset if it wasnt already
- display = day;
- element_ptr->count_days = TRUE;
- }
- else
- element_ptr->count_days = FALSE;
-
- years = months = weeks = days = hours = minutes = seconds = 0;
-
- if (display & year || display & month) // Otherwise simply calulate seconds
- {
- Secs2Date(current_secs, ¤t_daterec);
- Secs2Date(target_secs, &target_daterec);
-
- four_years = (the_secs / FOUR_YEAR_SECS); // FOUR_YEAR_SECS is a constant - 1461 days
- the_secs -= four_years * FOUR_YEAR_SECS;
-
- year_index = current_daterec.year % 4; // 0=leap,1-3=not leap
-
- if (in_past)
- {
- if (current_daterec.month < 3) year_index--;// Before March use the previous year
- if (year_index == -1 || year_index == 3) year_index = 1;
- else if (year_index == 1) year_index = 3;
- }
- else if (current_daterec.month > target_daterec.month && target_daterec.month >= 3)
- year_index++; // After february use the next year
-
- keep_counting = TRUE;
- while (keep_counting) // Counts years until secs < the next year
- {
- if (year_index == 4 || year_index == 0)
- next_year = LEAP_YEAR_SECS;
- else
- next_year = YEAR_SECS;
-
- if (the_secs < next_year)
- keep_counting = FALSE;
- else
- {
- the_secs-= next_year;
- years++;
- year_index++;
- }
- }
- years += four_years * 4;
-
- if (display & month)
- {
- month_index = current_daterec.month;
- if (in_past)
- month_index--;
- else
- {
- /****************************************************************
- * The upcoming code deals with the following type of problem: *
- * 1/30/94 -> 3/1/94 = one month away (2/30) doesn't exist *
- * so the current time is forced back to 1/28 (the same *
- * number of days as the month prior to the target) *
- * "1 month 1 day" is calculated *
- ****************************************************************/
- current_day = current_daterec.day;
- if (current_day > target_daterec.day)
- {
- current_day *= DAY_SECS; // Convert to seconds since beginning of month
- temp = Month_Secs(target_daterec.month - 1, year_index); // Find length in Secs of prior month
- if (current_day > temp) // Test if current date exists in prior month
- the_secs += current_day - temp; // Slide current back enough days to make it exist
- }
- /***************************************************************/
- }
-
- keep_counting = TRUE;
- while (keep_counting)
- {
- if (month_index == 13)
- month_index = 1;
- else if (month_index == 0)
- month_index = 12;
-
- next_month = Month_Secs (month_index, year_index);
-
- /****************************************************************
- * The upcoming code deals with the following type of problem: *
- * 4/30/94 -> 3/1/94 = would say "2mo 1dys *
- * instead "1 month 28 days" is correctly calculated *
- ****************************************************************/
- if (in_past)
- if (month_index == target_daterec.month-1)
- if (next_month < (current_daterec.day * DAY_SECS))
- keep_counting = FALSE;
- /***************************************************************/
-
- if (keep_counting)
- {
- if (the_secs < next_month)
- keep_counting = FALSE;
- else
- {
- the_secs -= next_month;
- months++;
- if (!in_past)
- month_index++;
- else
- month_index--;
- }
- }
- }
- if ( ~display & year)
- {
- months += years * 12;
- years = 0;
- }
- if (!months && display_ptr->hide_zeros) display -= month; // Dont show if its a zero
- }
- if (display & year)
- if (!years && display_ptr->hide_zeros) display -= year; // Dont show if its a zero
- }
-
- if (display & week)
- {
- weeks = the_secs / WEEK_SECS; // Calculate number of Weeks
- the_secs -= (weeks * WEEK_SECS);
- if (!weeks && display_ptr->hide_zeros) display -= week; // Dont show if its a zero
- }
-
- if (display & day)
- {
- days = the_secs / DAY_SECS; // Calculate number of Days
- the_secs -= (days * DAY_SECS);
- if (!days && display_ptr->hide_zeros) display -= day; // Dont show if its a zero
- }
-
- if (display & hour)
- {
- hours = the_secs / HOUR_SECS; // Calculate number of Hours
- the_secs -= (hours * HOUR_SECS);
- }
-
- if (display & minute)
- {
- minutes = the_secs / MINUTE_SECS;
- the_secs -= (minutes * MINUTE_SECS);
- }
-
- if (display & second) //Remove condition if we are going to convert to do noncalculated updates
- seconds = the_secs;
-
- if (display_ptr->fractional && ~display_ptr->last_item & second)
- {
- switch (display_ptr->last_item)
- {
- case year:
- fraction = (float)the_secs / next_year;
- places = YEAR_PLACES;
- break;
-
- case month:
- fraction = (float)the_secs / next_month;
- places = MONTH_PLACES;
- break;
-
- case week:
- fraction = (float)the_secs / WEEK_SECS;
- places = WEEK_PLACES;
- break;
-
- case day:
- fraction = (float)the_secs / DAY_SECS;
- places = DAY_PLACES;
- break;
-
- case hour:
- fraction = (float)the_secs / HOUR_SECS;
- places = HOUR_PLACES;
- break;
-
- case minute:
- fraction = (float)the_secs / MINUTE_SECS;
- places = MINUTE_PLACES;
- break;
-
- }
- Float2String (fraction, element_ptr->fractional, places);
- }
- else element_ptr->fractional[0] = 0;
-
- display |= display_ptr->last_item;
- element_ptr->inPast = in_past;
- element_ptr->display_items = display;
- element_ptr->last_item = display_ptr->last_item;
- element_ptr->year = years;
- element_ptr->month = (unsigned long)months;
- element_ptr->week = weeks;
- element_ptr->day = days;
- element_ptr->hour = hours;
- element_ptr->minute = minutes;
- element_ptr->second = seconds;
-
- element_ptr->clockDisplay = (hours < 24 && display_ptr->clockDisplayEnable); //Turn on Clock display
- }
-
-
- /*====================================================================================
- Name: Assemble_Time_String
- Description:
- Send it a Display_Elements_Ptr which has been previously filled by
- Calculate_Rel_Time_Str, send it a string and a Boolean and it returned the
- formatted relative time string.
- Last revision:
- __________________________________________________________________________________
-
- Input:
- Display_Elements_Ptr pointer to a filled Display_Elements
- Str255 pointer to a string to be returned
- Boolean abrev_string TRUE = abbreviated string returned
- FALSE = full string returned
- Output:
- Str255 formatted output string
- =====================================================================================*/
- void Assemble_Time_String (Display_Elements_Ptr element_ptr, Str255 the_str, Boolean abrev_string)
- {
- Boolean singular;
- Display_Items display, frac_display = 0;
- Str255 temp_str;
-
- the_str[0] = 0;
-
- display = element_ptr->display_items;
- if (element_ptr->fractional[0])
- frac_display = element_ptr->last_item;
-
- if (element_ptr->count_days)
- {
- GetIndString(temp_str, Time_StringsID, countdaysString);
- Append_String (the_str, temp_str, 1);
- Append_Num2String (element_ptr->day,the_str,FALSE);
- return;
- }
-
-
- if (display & year)
- {
- singular = FALSE;
- Append_Num2String (element_ptr->year,the_str,FALSE);
- if (frac_display & year)
- Append_String (the_str, element_ptr->fractional, 0);
- else
- if (element_ptr->year == 1)
- singular = TRUE;
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, yrString);
- else
- {
- GetIndString(temp_str, Time_StringsID, singular ? yearString:yearsString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
-
-
- if (display & month)
- {
- singular = FALSE;
- Append_Num2String (element_ptr->month,the_str,FALSE);
- if (frac_display & month)
- Append_String (the_str, element_ptr->fractional, 0);
- else if (element_ptr->month == 1) singular = TRUE;
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, moString);
- else
- {
- GetIndString(temp_str, Time_StringsID, singular ? monthString:monthsString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
-
-
- if (display & week)
- {
- singular = FALSE;
- Append_Num2String (element_ptr->week,the_str,FALSE);
- if (frac_display & week)
- Append_String (the_str, element_ptr->fractional, 0);
- else if (element_ptr->week == 1) singular = TRUE;
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, wkString);
- else
- {
- GetIndString(temp_str, Time_StringsID, singular ? weekString:weeksString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
-
-
- if (display & day)
- {
- singular = FALSE;
- Append_Num2String (element_ptr->day,the_str,FALSE);
- if (frac_display & day)
- Append_String (the_str, element_ptr->fractional, 0);
- else if (element_ptr->day == 1) singular = TRUE;
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, dString);
- else
- {
- GetIndString(temp_str, Time_StringsID, singular ? dayString:daysString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
-
-
- if (element_ptr->clockDisplay)
- {
- Append_Num2String (element_ptr->hour,the_str,FALSE);
- Append_Seperator(the_str);
- Append_Num2String (element_ptr->minute,the_str,TRUE);
- if (frac_display & minute)
- Append_String (the_str, element_ptr->fractional, 0);
- if (display & second)
- {
- Append_Seperator(the_str);
- Append_Num2String (element_ptr->second,the_str,TRUE);
- }
- the_str[++the_str[0]] = ' ';
- }
- else
- {
- if (display & hour)
- {
- singular = FALSE;
- Append_Num2String (element_ptr->hour,the_str,FALSE);
- if (frac_display & hour)
- Append_String (the_str, element_ptr->fractional, 0);
- else if (element_ptr->hour == 1) singular = TRUE;
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, hString);
- else
- {
- GetIndString(temp_str, Time_StringsID, singular ? hourString:hoursString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
-
- if (display & minute)
- {
- singular = FALSE;
- Append_Num2String (element_ptr->minute,the_str,FALSE);
- if (frac_display & minute)
- Append_String (the_str, element_ptr->fractional, 0);
- else if (element_ptr->minute == 1) singular = TRUE;
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, mString);
- else
- {
- GetIndString(temp_str, Time_StringsID, singular ? minuteString:minutesString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
-
- if (display & second)
- {
- Append_Num2String (element_ptr->second,the_str,FALSE);
-
- if (abrev_string)
- GetIndString(temp_str, Time_StringsID, sString);
- else
- {
- GetIndString(temp_str, Time_StringsID, element_ptr->second == 1 ? secondString:secondsString);
- the_str[++the_str[0]] = NUMBER_SEPARATOR;
- }
- Append_String (the_str, temp_str, 1);
- }
- }
-
- GetIndString(temp_str, Time_StringsID, element_ptr->inPast ? agoString:untilString);
- Append_String (the_str, temp_str, 0);
- }
-
-
- /*********************************************
- * Setup_Significant:
- * Sets Display to most significant Event
- **********************************************/
- void Setup_Significant (Display_Items* display, Display_Type_Ptr display_ptr,
- unsigned long the_secs)
- {
- if (the_secs < DAY_SECS && *display & hour && *display & minute && display_ptr->allow_clock_display)
- {
- display_ptr->clockDisplayEnable = TRUE;
- if (display_ptr->display_items & second)
- {
- *display = (hour + minute + second);
- display_ptr->last_item = second;
- }
- else
- {
- *display = (hour + minute);
- display_ptr->last_item = minute;
- }
- return;
- }
- *display = display_ptr->last_item;
- display_ptr->clockDisplayEnable = FALSE;
- if (display_ptr->display_items & second) *display = second;
- if (display_ptr->display_items & minute && the_secs >= MINUTE_SECS) *display = minute;
- if (display_ptr->display_items & hour && the_secs >= HOUR_SECS) *display = hour;
- if (display_ptr->display_items & day && the_secs >= DAY_SECS) *display = day;
- if (display_ptr->display_items & week && the_secs >= WEEK_SECS) *display = week;
- if (display_ptr->display_items & month && the_secs >= (31 * DAY_SECS)) *display = month;
- if (display_ptr->display_items & year && the_secs >= YEAR_SECS) *display = year;
- display_ptr->last_item = *display;
- }
-
-
- /*********************************************
- * Determine_Display_Elements:
- * Sets Display Elements to be calculated
- **********************************************/
- void Determine_Display_Elements (Display_Type_Ptr display)
- {
-
- // FIND THE SMALLEST DISPLAY ITEM CHECKED
- if (display->display_items & year) display->last_item = year;
- if (display->display_items & month) display->last_item = month;
- if (display->display_items & week) display->last_item = week;
- if (display->display_items & day) display->last_item = day;
- if (display->display_items & hour) display->last_item = hour;
- if (display->display_items & minute) display->last_item = minute;
- if (display->display_items & second) display->last_item = second;
-
- // DETERMINE IF CLOCK DISPLAY WILL BE USED
- if (display->display_items & hour && display->display_items & minute && display->allow_clock_display)
- display->clockDisplayEnable = TRUE;
- else
- display->clockDisplayEnable = FALSE;
-
- }
-
-
- /*******************************************
- * Month_Secs:
- * Returns the number of seconds in a specified month
- **********************************************/
- unsigned long Month_Secs(short the_month, short the_year)
- {
- switch (the_month)
- {
- case 2: // February
- if ((the_year % 4) == 0) // Leap Year
- return 2505600; // 29 days of seconds
- else
- return 2419200; // 28 days of seconds
- break;
-
- case 4: // April
- case 6: // June
- case 9: // September
- case 11: // November
- return 2592000; // 30 days of seconds
- break;
-
- default: // The Rest of the months
- return 2678400; // 31 days of seconds
- break;
- }
- }
-
- /*====================================================================================
- Name: Append_String
- Description:
- send it a source string and an append string as well as a flag
- which will add a trailing space to the output string
- Last revision:
- __________________________________________________________________________________
-
- Input:
- source_string
- append_string
- trailing_spaces flag
- Output:
- source_string will be the original string + append string + trailing_space (if any)
- =====================================================================================*/
- void Append_String (Str255 source_string, Str255 append_string, Boolean trailing_space)
- {
- BlockMove(append_string + 1, source_string + source_string[0] + 1L, append_string[0]);
- source_string[0] += append_string[0];
- if (trailing_space)
- {
- source_string[source_string[0]+1] = ' ';
- source_string[0]++;
- }
- }
-
- /*====================================================================================
- Name: Append_Num2String
- Description:
- send it a number and it will return that number appended to the
- string which you specify. Also, if leading_zero is true, it will first add a
- zero to the string if the number is a single digit
- Last revision:
- __________________________________________________________________________________
-
- Input:
- the_num number to append onto the string
- the_string string to append onto
- leading_zero flag TRUE = add a leading zero to single digit numbers
- FALSE = don't add a leading zero
- Output:
- the_string
- =====================================================================================*/
- void Append_Num2String (long the_num, Str255 the_string, Boolean leading_zero)
- {
- Str255 temp_str;
-
- NumToString(the_num,temp_str);
- if (leading_zero && the_num < 10)
- the_string[++the_string[0]] = '0';
- BlockMove(temp_str + 1, the_string + the_string[0] + 1L, temp_str[0]);
- the_string[0] += temp_str[0];
- }
-
- /*********************************************
- *
- * Append_Seperator: appends the Time_Seperator character to the sent string
- *
- *
- **********************************************/
- void Append_Seperator( Str255 the_str )
- {
- the_str[++the_str[0]] = ':';
- }
-
- /*====================================================================================
- Name: Float2String
- Description:
- Send it a float number less than 1 (just decimal places) and
- it will append a decimal point and the number to the source string. The number
- will have exactly 'places' number of digits.
- THIS IS NOT A GREAT ROUTINE. IT ONLY DEALS WITH NUMBERS LESS THAN 1 AND GREATER
- THAN 0.
- Last revision:
- __________________________________________________________________________________
-
- Input:
- the_num a float number greater than 0 and less than 1
- the_string output string
- places number of decimal places you want in the output
- Output:
- the_string
- =====================================================================================*/
- void Float2String (float the_num, Str255 the_string, short places)
- {
- Str255 dec_str;
- register short i;
-
- the_string[1] = '.';
- the_string[0] = 1;
- for (i=1; i <= places; i++)
- {
- the_num *= 10;
- NumToString(the_num,dec_str);
- the_num -= (int)the_num;
- the_string[++the_string[0]] = dec_str[1];
- }
- }
-